package com.zw.syncopenapi.common;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.ReadListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Excel 文件工具类
 * Created by Jack on 2025/9/29.
 */
@Service
public class ExcelFileUtils {

    @Value("${tempFilePath}")
    private String tempFilePath;

    /**
     * 获取指定路径下所有 Excel 文件（不递归子目录）
     * @param dirPath 目录路径（如 "E:\\数据报表"）
     * @return Excel 文件数组，若无文件则返回空数组
     */
    public File[] getAllExcelFiles(String dirPath) {
        File dir = new File(dirPath);
        if (!dir.exists() || !dir.isDirectory()) {
            throw new IllegalArgumentException("路径不存在或不是目录: " + dirPath);
        }

        // 仅筛选 .xlsx 和 .xls 文件
        return dir.listFiles(file ->
                file.isFile() &&
                        (file.getName().endsWith(".xlsx"))
        );
    }

    /**
     * 获取最近修改的 Excel 文件
     * @param dirPath 目录路径
     * @return 最近修改的 Excel 文件，若无则返回 null
     */
    public File getLatestModifiedExcelFile(String dirPath) {
        File[] excelFiles = getAllExcelFiles(dirPath);
        if (excelFiles == null || excelFiles.length == 0) {
            return null;
        }

        // 按修改时间降序排序
        Arrays.sort(excelFiles, Comparator.comparingLong(File::lastModified).reversed());
        return excelFiles[0];
    }

    /**
     * 计算文件的 MD5 编码
     * @param file 目标文件
     * @return MD5 字符串（小写）
     */
    public String calculateFileMD5(File file) throws IOException, NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[8192];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                md.update(buffer, 0, len);
            }
        }
        byte[] digest = md.digest();
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    /**
     * 打印最近修改的 Excel 文件的 MD5
     * @param dirPath 目录路径
     */
    public void printLatestExcelFileMD5(String dirPath) {
        try {
            File latestExcelFile = getLatestModifiedExcelFile(dirPath);
            if (latestExcelFile == null) {
                System.out.println("目录下没有 Excel 文件: " + dirPath);
                return;
            }

            System.out.println("最近修改的 Excel 文件: " + latestExcelFile.getName());
            System.out.println("修改时间: " + new Date(latestExcelFile.lastModified()));
            System.out.println("MD5 编码: " + calculateFileMD5(latestExcelFile));

        } catch (Exception e) {
            System.err.println("错误: " + e.getMessage());
        }
    }

    /**
     * 提取 Excel 文件 B 列的所有字符串（高性能流式读取）
     * @param excelFile Excel 文件
     * @return B 列的字符串数组（跳过空值）
     */
    public List<String> getColumnBAsStringArray(File excelFile) {
        List<String> validOaids = new ArrayList<>();
        // 正则优化
        Pattern pattern = Pattern.compile(".*[?&]oaid=([a-zA-Z0-9]{32})(?:&|$).*");

        EasyExcel.read(excelFile, new ReadListener<Object>() {
            @Override
            public void invoke(Object rowData, AnalysisContext context) {
                ReadCellData<?> cellData = (ReadCellData<?>) context.readRowHolder().getCellMap().get(1);
                if (cellData == null) return;
                String cellValue = cellData.getStringValue();
                // 双重条件过滤
                if (!cellValue.contains("__OAID__")) {
                    Matcher matcher = pattern.matcher(cellValue);
                    if (matcher.matches()) {
                        validOaids.add(matcher.group(1)); // 提取第1个捕获组（32位字符）
                    }
                }
            }
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                System.out.println("有效OAID提取完成，共 " + validOaids.size() + " 条");
            }
        }).sheet().doRead();
        return validOaids;
    }

    /**
     * 将字符串列表写入临时文本文件（每行一个字符串）
     * @param stringList 字符串列表
     * @param fileName 指定文件名（如不指定则自动生成）
     * @return 生成的TXT文件对象
     * @throws IOException 写入失败时抛出
     */
    public String convertListToTextFile(List<String> stringList, String fileName) throws IOException {
        // 确保临时文件目录存在
        File tempDir = new File(tempFilePath);
        if (!tempDir.exists()) {
            tempDir.mkdirs();
        }

        // 确定输出文件路径
        String outputFileName = (fileName != null) ? fileName : "temp_" + UUID.randomUUID().toString() + ".txt";
        File outputFile = new File(tempFilePath + outputFileName);

        // 写入数据
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile))) {
            for (String line : stringList) {
                writer.write(line);
                writer.newLine(); // 换行
            }
        }

        System.out.println("文件已生成: " + outputFile.getAbsolutePath());
        return outputFile.getPath();
    }

    /**
     * 将字符串列表写入临时文本文件（自动生成文件名）
     * @param stringList 字符串列表
     * @return 生成的TXT文件对象
     * @throws IOException 写入失败时抛出
     */
    public String convertListToTextFile(List<String> stringList) throws IOException {
        return convertListToTextFile(stringList, null);
    }
}